---
title: .family
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

Bevor sie das lesen, sollten sie sich über [Providers](/docs/concepts/providers) und [Wie man sie ausließt](/docs/concepts/reading) informieren.
In diesem Teil werden wir im Detail über den Provider-Modifikator `.family` sprechen.

Der `.family`-Modifikator hat einen Zweck: Einen Provider aus externen Werten zu erstellen.

Einige häufige Anwendungsfälle für `family` wären:

- Kombination von [FutureProvider] mit `.family`, um eine `Message` anhand ihrer ID zu laden
- Übergabe der aktuellen `Locale` an einen Provider, so dass wir mit Übersetzungen umgehen können:

## Verwendung

Die `family`'s funktionieren, indem sie dem Provider einen zusätzlichen Parameter hinzufügen.
Dieser Parameter kann dann in unserem Provider frei verwendet werden, um einen Zustand zu erzeugen.

Zum Beispiel könnten wir `family` mit [FutureProvider] kombinieren, um eine `Message` anhand ihrer ID zu laden:

```dart
final messagesFamily = FutureProvider.family<Message, String>((ref, id) async {
  return dio.get('http://my_api.dev/messages/$id');
});
```

Bei der Verwendung unseres `messagesFamily`-Providers wird die Syntax dann leicht geändert.  
Die übliche Syntax wird nicht mehr funktionieren

```dart
Widget build(BuildContext context, WidgetRef ref) {
  // Error – messagesFamily is not a provider
  final response = ref.watch(messagesFamily);
}
```

Stattdessen müssen wir einen Parameter an `messagesFamily` übergeben:

```dart
Widget build(BuildContext context, WidgetRef ref) {
  final response = ref.watch(messagesFamily('id'));
}
```

:::info
Es ist möglich, eine `family` mit verschiedenen Parametern gleichzeitig zu verwenden.  
Zum Beispiel könnten wir eine `titleFamily` verwenden, um sowohl die französische als auch die englische
Übersetzungen gleichzeitig zu lesen:

```dart
@override
Widget build(BuildContext context, WidgetRef ref) {
  final frenchTitle = ref.watch(titleFamily(const Locale('fr')));
  final englishTitle = ref.watch(titleFamily(const Locale('en')));

  return Text('fr: $frenchTitle en: $englishTitle');
}
```

:::

## Parameter Einschränkungen

Damit `family`'s korrekt funktionieren, ist es wichtig, dass der an einen Provider 
übergebene Parameter einen konsistenten `hashCode` und `==` haben muss.

Idealerweise sollte der Parameter entweder ein primitiver Datentyp (bool/int/double/String),
eine Konstante (Provider) oder ein immutable Objekt, das `==` und `hashCode` überschreibt, sein.

### _BEVORZUGE_ die Benutzung von `autoDispose` wenn der Parameter keine Konstante ist:

Sie möchten vielleicht `family`'s verwenden, um die Eingabe eines Suchfeldes an Ihren Provider zu übergeben.
Dieser Wert kann sich jedoch häufig ändern und nie wieder verwendet werden.  
Dies könnte zu Memory leaks führen, da ein Provider standardmäßig nie zerstört wird, 
selbst wenn er nicht mehr verwendet wird.

Die Verwendung von `.family` und `.autoDispose` behebt dieses Speicherleck:

```dart
final characters = FutureProvider.autoDispose.family<List<Character>, String>((ref, filter) async {
  return fetchCharacters(filter: filter);
});
```

## Übergabe mehrerer Parameter an eine family

`family`'s  haben keine eingebaute Unterstützung für die Übergabe mehrerer Werte an einen Provider.

Andererseits kann dieser Wert _beliebig_ sein (solange er mit den
den zuvor genannten Einschränkungen übereinstimmt).

Dazu gehört:

- Ein Tuple aus [tuple](http://pub.dev/packages/tuple)
- Objekte mit [Freezed] oder [built_value](https://pub.dev/packages/built_value) generiert 
- Objekte die [equatable](https://pub.dev/packages/equatable) benutzen

Hier ist ein Beispiel mit [Freezed] und [equatable]:

<Tabs
  groupId="family"
  defaultValue="freezed"
  values={[
    { label: 'Freezed', value: 'freezed', },
    { label: 'Equatable', value: 'equatable', },
  ]}
>

<TabItem value="freezed">

```dart
@freezed
abstract class MyParameter with _$MyParameter {
  factory MyParameter({
    required int userId,
    required Locale locale,
  }) = _MyParameter;
}

final exampleProvider = Provider.autoDispose.family<Something, MyParameter>((ref, myParameter) {
  print(myParameter.userId);
  print(myParameter.locale);
  // Benutze userId/locale
});

@override
Widget build(BuildContext context, WidgetRef ref) {
  int userId; // Lesen Sie die Benutzer-ID von irgendwoher
  final locale = Localizations.localeOf(context);

  final something = ref.watch(
    exampleProvider(MyParameter(userId: userId, locale: locale)),
  );

  ...
}
```

</TabItem>
<TabItem value="equatable">

```dart
class MyParameter extends Equatable  {
  MyParameter({
    required this.userId,
    required this.locale,
  });

  final int userId;
  final Locale locale;

  @override
  List<Object> get props => [userId, locale];
}

final exampleProvider = Provider.family<Something, MyParameter>((ref, myParameter) {
  print(myParameter.userId);
  print(myParameter.locale);
  // Benutze userId/locale
});

@override
Widget build(BuildContext context, WidgetRef ref) {
  int userId; // Lesen Sie die Benutzer-ID von irgendwoher
  final locale = Localizations.localeOf(context);

  final something = ref.watch(
    exampleProvider(MyParameter(userId: userId, locale: locale)),
  );

  ...
}
```
</TabItem>
</Tabs>

[freezed]: https://pub.dev/packages/freezed
[equatable]: https://pub.dev/packages/equatable
[futureprovider]: ../../providers/future_provider
